/*
   AAC encoder API
 */
#include "includes_fw.h"
#include "config_fw.h"
#include "lib_retina.h"
#include "mmpf_audio_ctl.h"
#include "mmpf_encapi.h"
#include "mmpf_usbvend.h"
#include "mmpf_timer.h"
#include "mmpf_usbuac.h"
#include "mmp_reg_usb.h"
#include "mmpf_3gpmgr.h"
#include "pcam_handler.h"
#if (SUPPORT_MP4) || (SUPPORT_MTS)
#include "mmpf_aacencapi.h"
#endif

#if SUPPORT_UAC

#if (UAC_SYNC_MODE_EN == 1)
MMP_ULONG ulUnchangeSampleCnt = 0;
//MMP_SHORT UACReadyBuf[32];
MMP_SHORT UACReadyBuf[MAX_AUDIN_SAMPLE_PER_MS * AUDIN_CHANNEL];//1ms buffer
#endif
MMP_ULONG ulDropSampleCnt = 0;
MMP_ULONG ulDummySampleCnt = 0;
MMP_LONG preFifoCnt = 0;
MMP_LONG postFifoCnt = 0;

#define ENC_INBUF_FRAME_NUM  (32 * PRC_SAMPLES_TIME) //(16)//(8) How many ring buffer slot

#define READYFRAME_HIGHBOUND_TH  (ENC_INBUF_FRAME_NUM * 3 / 4)
#define READYFRAME_LOWBOUND_TH   (ENC_INBUF_FRAME_NUM / 4)
#define READYFRAME_MIDBOUND_TH   (ENC_INBUF_FRAME_NUM / 2)

//#define ENC_MAX_SAMPLES  ( 48 * AUDIN_CHANNEL *  ENC_SAMPLES_TIME )// 48000 / 1000 * 2 ch * ENC_SAMPLES_TIME ms = 384.
//#define ENC_INBUF_SIZE  (ENC_MAX_SAMPLES*ENC_INBUF_FRAME_NUM)  

#if DRAM_SIZE <= 2
__align(16) MMP_USHORT gAudInBuf[MAX_AUDIN_SAMPLE_PER_MS * AUDIN_CHANNEL * ENC_INBUF_FRAME_NUM];
#endif

MMP_ULONG glENC_MAX_SAMPLES;

void MMPF_Audio_3rdPartyInit(void);
void MMPF_Audio_3rdPartyExit(void);
void MMPF_Audio_3rdPartyEncode(MMP_SHORT *outPtr,MMP_SHORT *inPtr,MMP_SHORT samples);

extern AUDIO_ENC_INBUF_HANDLE AudioEncInBufHandle;
extern MMP_USHORT   gsAudioRecEvent;
extern MMP_ULONG au_offset;
extern MMP_ULONG audio_time;

#if (SUPPORT_MP4) || (SUPPORT_MTS)
extern MMP_BOOL MMPF_VIDMGR_GetMtsMuxModeEnable(void);
extern void MMPF_InitAACEncoder(void);  
extern void MMPF_SetAACRecParameter(MMP_ULONG bitrate, MMP_ULONG sampleRate);
extern MMP_BOOL MMPF_VIDMGR_GetMP4Enable(void);
extern MMP_BOOL MMPF_VIDMGR_GetMtsMuxModeEnable(void);
extern MMP_BOOL MMPF_VIDMGR_GetMP4Enable(void);

extern MMPF_VIDMGR_HANDLE          m_VidMgrHandle[1];    
extern MMPF_OS_FLAGID          SYS_Flag_Hif;
#endif

//MMP_SHORT   gsAACEncInBuf[ENC_INBUF_SIZE];
MMP_SHORT   gsAudioSamplesPerFrame,gsInAudioSamplesPerFrame ;
//----------------------------------------

//MMP_ULONG glAudioBufferStart ;
//MMP_ULONG glAudioBuffer_ReaderPtr ;
//MMP_ULONG glAudioBuffer_ReaderHighPtr ;
//MMP_ULONG glAudioBuffer_WriterHighPtr;
//MMP_ULONG glAudioBuffer_WriterPtr ;
//MMP_ULONG glAudioBuffer_ProcessedPtr ;
//MMP_ULONG glAudioBuffer_ProcessedHighPtr ;
MMP_UBYTE gbAud1stInToken = 0  ;

//MMP_USHORT gsTxBufferSizeByMs;
//MMP_USHORT gsTotalRingBufferSize;

//extern MMP_ULONG	Image$$ALL_SRAM$$Base;

void MMPF_Audio_TimerISR(void)
{
   MMP_USHORT csr;
 	csr = UsbReadTxEpCSR(PCCAM_AU_EP_ADDR);
 	if(gbAud1stInToken==0) {
		 if(csr & TX_UNDERRUN_BIT) {
			gbAud1stInToken = 1;
			RTNA_DBG_Str(0,"TX_UNDERRUN_BIT\r\n");
		 }
		 //RTNA_DBG_PrintShort(0, csr);
 	}
	else{
		MMPF_Audio_Tx(gsAudioSamplesPerFrame/ENC_SAMPLES_TIME);
    }
}

void MMPF_Audio_TimerOpen(MMP_ULONG us,MMPF_TIMER_ID id)
{
    dbg_printf(3,"#open aud timer\r\n");
    MMPF_Timer_OpenUs(id, us, MMPF_Audio_TimerISR); 
    MMPF_Timer_OpenInterrupt(id);
    MMPF_Timer_EnableInterrupt(id, MMP_TRUE);

    au_offset=0;
    audio_time = 0;
}

void MMPF_Audio_TimerClose(MMPF_TIMER_ID id)
{
    MMPF_Timer_EnableInterrupt(id, MMP_FALSE);
    MMPF_Timer_Close(id);
    dbg_printf(3,"#stop aud timer\r\n");
}

void MMPF_Audio_InitEncoder(MMP_SHORT samples_per_frame)
{
    //glAACDataEncoded = 0;
    MMP_SHORT i,*ptr;

    //gsTxBufferSizeByMs = (samples_per_frame / ENC_SAMPLES_TIME) * 2;  // By Byte per ms
    //gsTotalRingBufferSize = TOTAL_BUFFER_MS * gsTxBufferSizeByMs;

    //glAudioBufferStart = (MMP_ULONG)&Image$$ALL_SRAM$$Base - gsTotalRingBufferSize;// - 0x200;
	//glAudioBuffer_ReaderPtr = 0;
	//glAudioBuffer_ReaderHighPtr = 0;
	//glAudioBuffer_WriterPtr = (MIDER_BOUND * gsTxBufferSizeByMs);
	//glAudioBuffer_WriterHighPtr = 0;
	//glAudioBuffer_ProcessedPtr = (MIDER_BOUND * gsTxBufferSizeByMs);
	//glAudioBuffer_ProcessedHighPtr = 0;
	
	//glENC_MAX_SAMPLES = ( samples_per_frame * AUDIN_CHANNEL *  ENC_SAMPLES_TIME );
	//Truman@121101 The caller of MMPF_Audio_InitEncoder() already * AUDIN_CHANNEL. Here does not * AUDIN_CHANNEL to save buffer size.
	glENC_MAX_SAMPLES = ( samples_per_frame * ENC_SAMPLES_TIME );
//	glENC_MAX_SAMPLES = ( 48 * AUDIN_CHANNEL *  ENC_SAMPLES_TIME );
	
    gsAudioRecEvent = 0 ;
    AudioEncInBufHandle.rdPtr=0;
    AudioEncInBufHandle.wrPtr=0;
    AudioEncInBufHandle.prPtr=0;
    AudioEncInBufHandle.rdWrap=0;
    AudioEncInBufHandle.wrWrap=0;
    AudioEncInBufHandle.prWrap=0;
    AudioEncInBufHandle.bufSize = (glENC_MAX_SAMPLES * ENC_INBUF_FRAME_NUM) * sizeof(MMP_SHORT);
    
    ulDropSampleCnt = 0;
	ulDummySampleCnt = 0;

    gsAudioSamplesPerFrame = samples_per_frame;
    gsInAudioSamplesPerFrame =  samples_per_frame;
    #if DRAM_SIZE <= 2
    AudioEncInBufHandle.bufBase = (MMP_ULONG)gAudInBuf;
    #else
    AudioEncInBufHandle.bufBase = SRAM_AREA_FOR_CRITICAL_REGION - AudioEncInBufHandle.bufSize;// - 0x200;
    #endif
	
	gbAud1stInToken = 0;
	memset((void*)AudioEncInBufHandle.bufBase , 0 , AudioEncInBufHandle.bufSize);

    dbg_printf(3,"bufBase: 0x%x, bufSize: 0x%x\r\n", AudioEncInBufHandle.bufBase, AudioEncInBufHandle.bufSize);
    dbg_printf(3,"gsAudioSamplesPerFrame = %d\r\n", gsAudioSamplesPerFrame);

    // fill zero to 1st 8 frames
    ptr = (MMP_SHORT *)MMPF_Audio_GetWrPtr();
    for(i=0;i<gsAudioSamplesPerFrame*READYFRAME_MIDBOUND_TH;i++) {
        ptr[i] = 0 ;
    }
    for(i=0;i<READYFRAME_MIDBOUND_TH;i++) {
        MMPF_Audio_UpdateWrPtr(gsAudioSamplesPerFrame);
    }    

    //for(i=0 ; i < READYFRAME_MIDBOUND_TH ; i++){
    //    MMPF_Audio_EncodeFrame();
    //}

    MMPF_Audio_3rdPartyInit() ;

}


void MMPF_Audio_ExitEncoder(void)
{
    MMPF_Audio_3rdPartyExit();
}

#if (CUSTOMER == PNS)
MMP_BOOL GTKLIB_EN=1;
#endif
void MMPF_Audio_EncodeFrame(void)
{
    int size;
    MMP_SHORT *inPtr,*outPtr ;
    MMP_BOOL uac_en = 0, ts_mp4_en = 0;

    /* encode one frame */
    /* a stereo encoder always needs two channel input */
    // 3rd Party algorithm put here

#if (SUPPORT_AUDIO_PROCESSING_TASK)  // support audio processing in Task            
    OS_CPU_SR   cpu_sr = 0;
enc_entry:    
    IRQ_LOCK(
        size = MMPF_Audio_GetSizeByType(SIZE_CAN_PR);
    )

    if(size < 0) {
        dbg_printf(3,"#Enc.bad.PR : %d\r\n",size);
    }

    if(size >=  (gsAudioSamplesPerFrame*PRC_SAMPLES_TIME << 1) ) 
    {

        uac_en = (PCAM_USB_GetAudioWorkMode(MMPF_AUDIO_WORK_MODE_UAC)== MMPF_AUDIO_WORK_STATUS_DONE) ? 1 : 0;
        ts_mp4_en = (PCAM_USB_GetAudioWorkMode(MMPF_AUDIO_WORK_MODE_TS_MP4) == MMPF_AUDIO_WORK_STATUS_DONE) ? 1 : 0;

        //MMP_SHORT *inPtr2 ;
        inPtr = (MMP_SHORT *)MMPF_Audio_GetPrPtr();
        outPtr = inPtr;
        //if(size!=gsAudioSamplesPerFrame*PRC_SAMPLES_TIME<<1) {
        //    dbg_printf(3,"#PR size:%d\r\n",size);
        //}
#if (CUSTOMER == PNS)
        if(GTKLIB_EN)
#endif
        MMPF_Audio_3rdPartyEncode(outPtr,inPtr,/*gsAudioSamplesPerFrame*/gsInAudioSamplesPerFrame*PRC_SAMPLES_TIME );
        //IRQ_LOCK( 
        //    MMPF_Audio_UpdatePrPtr(gsAudioSamplesPerFrame*PRC_SAMPLES_TIME );
        //)
        // Go back to encode again if more samples
        goto enc_entry;
    }

#else  // without audio processing in ISR

    size = MMPF_Audio_GetSizeByType(SIZE_CAN_PR) ;
    if(size < 0) {
        dbg_printf(3,"#Enc.bad.PR : %d\r\n",size);
    }
    if(size >=  (gsAudioSamplesPerFrame*PRC_SAMPLES_TIME << 1) ) {
        inPtr = (MMP_SHORT *)MMPF_Audio_GetPrPtr() ; 
        outPtr = inPtr ;
        //if(size!=gsAudioSamplesPerFrame*PRC_SAMPLES_TIME<<1) {
        //    dbg_printf(3,"#PR size:%d\r\n",size);
        //}
        MMPF_Audio_3rdPartyEncode(outPtr,inPtr,/*gsAudioSamplesPerFrame*/gsInAudioSamplesPerFrame*PRC_SAMPLES_TIME );
        MMPF_Audio_UpdatePrPtr(gsAudioSamplesPerFrame*PRC_SAMPLES_TIME );
    }

#endif
}

#if AUDIO_LATENCY
MMP_ULONG aud_wr_cnt=0, aud_rd_cnt=0;
MMP_ULONG aud_wr_time=0, aud_rd_time=0;
MMP_ULONG aud_wr_cnt_cur=0;
MMP_ULONG glAudioDiff = 0;
#endif
void MMPF_Audio_UpdateWrPtr(MMP_ULONG size)
{
    MMP_ULONG sync = 0 ;
    // Drop this frame if buffer full
    if(MMPF_Audio_IsFull()) {
       //dbg_printf(3,"@F-(%d,%d,%d)\r\n",glAFETicks,glEncTicks,glPrcTicks);
       AudioEncInBufHandle.rdWrap = AudioEncInBufHandle.wrWrap ;
       AudioEncInBufHandle.rdPtr = AudioEncInBufHandle.wrPtr ;
       sync = 1; 
    }
	AudioEncInBufHandle.wrPtr += ( size << 1);
    if (AudioEncInBufHandle.wrPtr >=  AudioEncInBufHandle.bufSize ) {
    	AudioEncInBufHandle.wrPtr -=  AudioEncInBufHandle.bufSize  ;
    	AudioEncInBufHandle.wrWrap++;
#if AUDIO_LATENCY
		aud_wr_cnt = AudioEncInBufHandle.wrWrap;
		aud_wr_time = MMPF_BSP_GetTick();
#endif
    }
    if(sync) {
       AudioEncInBufHandle.prWrap = AudioEncInBufHandle.wrWrap ;
       AudioEncInBufHandle.prPtr = AudioEncInBufHandle.wrPtr ;
    }
}

void MMPF_Audio_UpdateRdPtr(MMP_ULONG size)
{
    AudioEncInBufHandle.rdPtr+=( size << 1);
    if (AudioEncInBufHandle.rdPtr >= AudioEncInBufHandle.bufSize ) {
        AudioEncInBufHandle.rdPtr -= AudioEncInBufHandle.bufSize ;
    	AudioEncInBufHandle.rdWrap++;
#if AUDIO_LATENCY
		aud_rd_cnt = AudioEncInBufHandle.rdWrap;
		if(aud_rd_cnt == aud_wr_cnt){
			aud_rd_time = MMPF_BSP_GetTick(); 
			glAudioDiff = aud_rd_time - aud_wr_time;
		}
#endif
    }
}


void MMPF_Audio_UpdatePrPtr(MMP_ULONG size)
{
    AudioEncInBufHandle.prPtr+=( size << 1);
    if (AudioEncInBufHandle.prPtr >= AudioEncInBufHandle.bufSize ) {
        AudioEncInBufHandle.prPtr -= AudioEncInBufHandle.bufSize ;
    	AudioEncInBufHandle.prWrap++;
    }
    //dbg_printf(3,"PR:%d,Wrap:%d\r\n",AudioEncInBufHandle.prPtr,AudioEncInBufHandle.prWrap);
}


void MMPF_Audio_UpdatePtrByType(AUDIO_SIZE_READ_TYPE type,MMP_ULONG size)
{
    MMP_ULONG ptr,wrap ;
    if(type==SIZE_CAN_WR) {
        ptr = AudioEncInBufHandle.wrPtr + (size << 1 );
        wrap = AudioEncInBufHandle.wrWrap ;
    } 
    else if(type==SIZE_CAN_PR) {
        ptr = AudioEncInBufHandle.prPtr + (size << 1 ); 
        wrap = AudioEncInBufHandle.prWrap ;
    }
    else if (type==SIZE_CAN_RD) {
        ptr = AudioEncInBufHandle.rdPtr + (size << 1 );
        wrap = AudioEncInBufHandle.rdWrap ;
    }
    if(ptr >= AudioEncInBufHandle.bufSize) {
        ptr-= AudioEncInBufHandle.bufSize ;
        wrap++ ;
    }
    if(type==SIZE_CAN_WR) {
        AudioEncInBufHandle.wrPtr = ptr; 
        AudioEncInBufHandle.wrWrap = wrap;
    }
    else if(type==SIZE_CAN_PR) {
        AudioEncInBufHandle.prPtr = ptr; 
        AudioEncInBufHandle.prWrap = wrap;
    }
    else if(type==SIZE_CAN_RD) {
        AudioEncInBufHandle.rdPtr = ptr; 
        AudioEncInBufHandle.rdWrap = wrap;
    }
}


MMP_ULONG MMPF_Audio_GetWrPtr(void)
{
	return AudioEncInBufHandle.bufBase + AudioEncInBufHandle.wrPtr;
}


MMP_ULONG MMPF_Audio_GetRdPtr(void)
{
	return AudioEncInBufHandle.bufBase + AudioEncInBufHandle.rdPtr;
}


MMP_ULONG MMPF_Audio_GetPrPtr(void)
{
	return AudioEncInBufHandle.bufBase + AudioEncInBufHandle.prPtr;
}


// How many frames can be send by USB
int MMPF_Audio_GetSizeByType(AUDIO_SIZE_READ_TYPE type)
{
    int wrap;
    int size,p1,p2;
    if(type == SIZE_CAN_WR) {
        wrap = AudioEncInBufHandle.wrWrap - AudioEncInBufHandle.rdWrap ; 
        p1 = AudioEncInBufHandle.wrPtr ;
        p2 = AudioEncInBufHandle.rdPtr ;
        if( (wrap < 0) || (wrap > 1) ) {
            //dbg_printf(3,"@W != R:%d,%d\r\n",AudioEncInBufHandle.wrWrap,AudioEncInBufHandle.rdWrap);
            return 0;
        }
    } 
    else if ( type == SIZE_CAN_PR ) {
        wrap = AudioEncInBufHandle.wrWrap - AudioEncInBufHandle.prWrap ; 
        p1 = AudioEncInBufHandle.wrPtr ;
        p2 = AudioEncInBufHandle.prPtr ;
        if( (wrap < 0) || (wrap > 1) ) {
           // dbg_printf(3,"@W != P:%d,%d\r\n",AudioEncInBufHandle.wrWrap,AudioEncInBufHandle.prWrap);
            return 0;
        }
    }
    else if ( type == SIZE_CAN_RD ) {
        wrap = AudioEncInBufHandle.prWrap - AudioEncInBufHandle.rdWrap ; 
        p1 = AudioEncInBufHandle.prPtr ;
        p2 = AudioEncInBufHandle.rdPtr ;
        if( (wrap < 0) || (wrap > 1) ) {
            //dbg_printf(3,"@P != R:%d,%d\r\n",AudioEncInBufHandle.prWrap,AudioEncInBufHandle.rdWrap);
            return 0;
        }
    }
    
    if(wrap==0) {
        size = (int)(p1 - p2 );
    } else {
        size = (int)(AudioEncInBufHandle.bufSize  + p1 - p2) ;
    }
    if(type == SIZE_CAN_WR) {
        size = AudioEncInBufHandle.bufSize - size ;
    }
    return size ;
    
}

extern MMP_USHORT gsAudioPreviewStartEnable;

MMP_ERR MMPF_Audio_Tx(MMP_SHORT samples)  // 500us timer base
{
//extern MMP_ULONG usbframecount ;
    MMP_USHORT 	usbin;
    int readySize = MMPF_Audio_GetSizeByType(SIZE_CAN_RD);
    usbin = gsAudioPreviewStartEnable;
    
    if(PCAM_USB_GetAudioWorkMode(MMPF_AUDIO_WORK_MODE_UAC) == MMPF_AUDIO_WORK_STATUS_DONE){

        if( uac_is_tx_busy()) {
        	//RTNA_DBG_Str(0, "TX BUSY!!!\r\n");
            return MMP_AUDIO_ERR_STREAM_OVERFLOW;
        }
    
        if( /*MMPF_Audio_IsEmpty()*/readySize < (samples+AUDIN_CHANNEL) << 1 ) {
            //dbg_printf(3,"@E : %d,(%d,%d,%d)-%d\r\n",readySize,glAFETicks,glEncTicks,glPrcTicks,usbframecount);
           // dbg_printf(3,"(%d,%d,%d,%d)\r\n",AudioEncInBufHandle.prWrap,AudioEncInBufHandle.rdWrap,AudioEncInBufHandle.prPtr,AudioEncInBufHandle.rdPtr);
        	//dbg_printf(3,"0");
            return MMP_AUDIO_ERR_STREAM_BUF_EMPTY;    
        }
    
        postFifoCnt = readySize;
        if(readySize >=  (READYFRAME_HIGHBOUND_TH*glENC_MAX_SAMPLES << 1) ) {
        	//RTNA_DBG_Str(0, "DP@ ");
        	//RTNA_DBG_Long(0, au_offset);
        	//RTNA_DBG_Str(0, "\r\n");
            samples += (AUDIN_CHANNEL) ;
           // dbg_printf(3,"S+:%d\r\n",samples);        
        }
        else  if(readySize <=READYFRAME_LOWBOUND_TH*glENC_MAX_SAMPLES << 1 ) {
        	//RTNA_DBG_Str(0, "dy@ ");
        	//RTNA_DBG_Long(0, au_offset);
        	//RTNA_DBG_Str(0, "\r\n");
            samples -= (AUDIN_CHANNEL);
          //  dbg_printf(3,"S-:%d\r\n",samples);     
        }
	
    	if ((postFifoCnt - preFifoCnt > 0) && (samples == 34)) //fifo depth changed
    	{
    		ulDropSampleCnt++;
    	}
    	if ((postFifoCnt - preFifoCnt < 0) && (samples == 30)) //fifo depth changed
    	{
    		ulDummySampleCnt++;
    	}

    	preFifoCnt = postFifoCnt;			

        //RTNA_DBG_Str(3, "s= ");
        //MMPF_DBG_Int(samples, -3);  // samples -> 48 for 24K, dual, 1ms
        //RTNA_DBG_Str(3,"\r\n");	
        //  dbg_printf(3,"s= %d\r\n",samples); // samples -> 48 for 24K, dual, 1ms    
        if(usbin){
            MMPF_Audio_Move2USBFifo(samples);
            uac_process_audio_data();
            MMPF_Audio_UpdateRdPtr(samples);
        }
    }

    return MMP_ERR_NONE ;    
}

void MMPF_Audio_Move2USBFifo(MMP_SHORT samples)
{
	AITPS_USB_CTL pUSB_CTL = AITC_BASE_USBCTL;
#if (UAC_SYNC_MODE_EN == 1)
	MMP_SHORT tmp1, tmp2, tmp3, tmp4, cnt;
#endif
    MMP_SHORT i ,*ptr , s;
    MMP_UBYTE smooth_on = FALSE;
    ptr = (MMP_SHORT *)MMPF_Audio_GetRdPtr();

#if (AUDEXT_DAC == WM8737) || (AUDEXT_DAC == WM8960)
    if((audio_time == 0) && (au_offset < 400))   // mute before 400ms
#else
    if((audio_time == 0) && (au_offset < 100))   // mute before 100ms
#endif
    {
        smooth_on = TRUE;
    }
	#if (UAC_SYNC_MODE_EN == 1)
	{
		s = ( AudioEncInBufHandle.bufSize - ((MMP_ULONG)AudioEncInBufHandle.rdPtr))>>1;
		if (samples >= 32)
		{
			if (s >= samples)
			{
				for(i=0; i<32; i++) {
	                if(smooth_on == TRUE)
	                    UACReadyBuf[i] = 8;
	                else
	                    UACReadyBuf[i] = ptr[i];
            	}
			}
			else {
				for (i=0; i<s; i++)	{
					if(smooth_on == TRUE)
	                    UACReadyBuf[i] = 8;
	                else
	                    UACReadyBuf[i] = ptr[i];
				}
				cnt = 32 - s;
				ptr = (MMP_SHORT *)AudioEncInBufHandle.bufBase;
	            for(i=0 ; i< cnt ;i++) {
	                if(smooth_on == TRUE)
	                    UACReadyBuf[s+i] = 8;  // mute
	                else
	                    UACReadyBuf[s+i] = ptr[i] ;
	            }
			}
		}
		else
		{
			if (s >= samples) {
				for (i=0; i<32; i++) {
					if (i < samples) {
						if(smooth_on == TRUE)
		                    UACReadyBuf[i] = 8;
		                else
		                    UACReadyBuf[i] = ptr[i];

						if (((i-1)%2 == 0)&&((i-3) >= 0)) {
							tmp1 = UACReadyBuf[i-1];	//L ch
							tmp2 = UACReadyBuf[i];		//R ch
							tmp3 = UACReadyBuf[i-2];	//R ch
							tmp4 = UACReadyBuf[i-3];	//L ch
						}
					}
					else {
						if (i%2 == 0)
							UACReadyBuf[i] = (tmp1 + tmp4)/2;	//duplicate
						else UACReadyBuf[i] = (tmp2 + tmp3)/2;	//duplicate
					}
				}
			}
			else {
				// if s < samples; then s must be less than 28
				for (i=0; i<s; i++)	{
					if(smooth_on == TRUE)
	                    UACReadyBuf[i] = 8;
	                else {
	                    UACReadyBuf[i] = ptr[i];
	                    if (((i-1)%2 == 0)&&((i-3) >= 0)) {
	                    	// handle special case: 2point at button of buffer, the other 2 on the top
							tmp4 = UACReadyBuf[i-1];	//L ch
							tmp3 = UACReadyBuf[i];		//R ch
						}
					}
				}
				
				cnt = samples - s;
				ptr = (MMP_SHORT *)AudioEncInBufHandle.bufBase;
				for (i=0 ; i< cnt ;i++) {
	                if(smooth_on == TRUE)
	                    UACReadyBuf[s+i] = 8;  // mute
	                else
	                    UACReadyBuf[s+i] = ptr[i];
					if (((i-1)%2 == 0)&&((i-3) >= 0)&&(cnt>=4)) {
							tmp1 = UACReadyBuf[i-1];	//L ch
							tmp2 = UACReadyBuf[i];		//R ch
						tmp3 = UACReadyBuf[i-2];	//R ch
						tmp4 = UACReadyBuf[i-3];	//L ch
						}
					else if (((i-1)%2 == 0) && ((i-1)>=0)) {
						tmp1 = UACReadyBuf[i-1];	//L ch
						tmp2 = UACReadyBuf[i];		//R ch
					}
	            }
	            for (i=0; i<(32-samples); i++) {
	            	if (i%2 == 0)
	            		UACReadyBuf[samples + i] = (tmp1 + tmp4)/2;
	            	else
	            		UACReadyBuf[samples + i] = (tmp2 + tmp3)/2;
				}
			}
		}
		for (i=0 ; i<32; i++) {
			pUSB_CTL->USB_FIFO_EP[PCCAM_AU_EP_ADDR].FIFO_W = UACReadyBuf[i];
		}
	}
	#else
    {
        s =  ( AudioEncInBufHandle.bufSize - ((MMP_ULONG)AudioEncInBufHandle.rdPtr))>>1 ;
        if(s >= samples) {
            for(i=0;i<samples;i++) {
                if(smooth_on == TRUE){
                #if 1
                    pUSB_CTL->USB_FIFO_EP[PCCAM_AU_EP_ADDR].FIFO_W = 8;  // mute
                #else
                    pUSB_CTL->USB_FIFO_EP[PCCAM_AU_EP_ADDR].FIFO_W = (ptr[i] >> 7);
                #endif
                }
                else{
                    pUSB_CTL->USB_FIFO_EP[PCCAM_AU_EP_ADDR].FIFO_W = ptr[i];
                }
            }
        } else {
            for(i=0;i< s ;i++) {
                if(smooth_on == TRUE){
                #if 1
                    pUSB_CTL->USB_FIFO_EP[PCCAM_AU_EP_ADDR].FIFO_W = 8;  // mute
                #else
                    pUSB_CTL->USB_FIFO_EP[PCCAM_AU_EP_ADDR].FIFO_W = (ptr[i] >> 7);
                #endif
                }
                else{
                    pUSB_CTL->USB_FIFO_EP[PCCAM_AU_EP_ADDR].FIFO_W = ptr[i] ;
                }
            }
            s = samples - s ;
            ptr = (MMP_SHORT *)AudioEncInBufHandle.bufBase;
            for(i=0;i< s ;i++) {
                if(smooth_on == TRUE){
                #if 1
                    pUSB_CTL->USB_FIFO_EP[PCCAM_AU_EP_ADDR].FIFO_W = 8;  // mute
                #else
                    pUSB_CTL->USB_FIFO_EP[PCCAM_AU_EP_ADDR].FIFO_W = (ptr[i] >> 7);
                #endif
                }
                else{
                    pUSB_CTL->USB_FIFO_EP[PCCAM_AU_EP_ADDR].FIFO_W = ptr[i] ;
                }
            }
        }
    }
    #endif
}

MMP_BOOL MMPF_Audio_IsEmpty(void)
{
    return MMPF_Audio_GetSizeByType(SIZE_CAN_RD)?0:1;
}

MMP_BOOL MMPF_Audio_IsFull(void)
{
    //return (AudioEncInBufHandle.freeSize <  (ENC_MAX_SAMPLES << 1) )?1:0;
    MMP_ULONG size ;
    size = MMPF_Audio_GetSizeByType(SIZE_CAN_WR) ;
    if(size < (glENC_MAX_SAMPLES << 1) ) {
        return 1 ;
    }
    return 0;
}

MMP_BOOL MMPF_Audio_IsSkipPostProcessing(void)
{
//    return gbSkipPostProcessing ;
    return 0;
}

#if !defined(BUILD_LIB) // add the 3rd party algorithm back later.
void MMPF_Audio_SkipPostProcessing(MMP_BOOL flag)
{
}

void MMPF_Audio_3rdPartyInit(void)
{
    if(PCAM_USB_GetAudioWorkMode(MMPF_AUDIO_WORK_MODE_TS_MP4) != MMPF_AUDIO_WORK_STATUS_DONE){

#if (SUPPORT_MTS)
        if(MMPF_VIDMGR_GetMtsMuxModeEnable())
        { 
            MMPF_MTS_TS aac_ts = {
            MTS_PID_ES_AUDIO_0,     // mmpf_mts.h define default pid
            MMP_TRUE,               // default 1
            0x01,                   // continuity
            MMP_FALSE,              // adaptation ctl
            MMP_TRUE,               // header section
            MMP_FALSE};             // PCR flag
         
            RTNA_DBG_Str(0, "MMPF_Audio_3rdPartyInit -> TS-AAC init\r\n.");

            MMPF_SetAACRecParameter(128000, 16000);

            MMPF_MTS_GeneratePesAudHeader(aac_pes_data);
            MMPF_MTS_GenerateTsHeader((MMP_UBYTE *) &aac_ts_header, &aac_ts);

            MMPF_InitAACEncoder();
        }
#endif

#if (SUPPORT_MP4)
        if(MMPF_VIDMGR_GetMP4Enable()){
            dbg_printf(3, "MMPF_Audio_3rdPartyInit -> MP4-AAC init\r\n");
            
            //MMPF_SetAACRecParameter(128000,16000);
            MMPF_SetAACRecParameter(128000,AUDIN_SAMPLERATE);
            MMPF_InitAACEncoder();
        }
#endif
    }
    
}

void MMPF_Audio_3rdPartyExit(void)
{
}

void MMPF_Audio_3rdPartyEncode(MMP_SHORT *outPtr,MMP_SHORT *inPtr,MMP_SHORT samples)
{
    MMP_ULONG cpu_sr;
    {
        //MMP_SHORT *pInbuf;
        //extern short *gsAACEncInVoiceBuf;
        //IRQ_LOCK(MMPF_Audio_UpdatePrPtr(samples);)
#if (SUPPORT_MP4) || (SUPPORT_MTS)
        MMP_UBYTE update_rd_ptr=0;
        if(m_VidMgrHandle[0].ulSequenceCnt>3){ //TBD
            //if(gsAACEncInVoiceBuf != NULL){ //AAC init done.
            MMPF_MMU_FlushCache((MMP_ULONG)inPtr, (MMP_ULONG)(samples*sizeof(short)));                
            AACvoiceinbuf(inPtr/*gsAACEncInBuf*/, samples/*gsAudioSamplesPerFrame*/);
            //}
        }
#endif
        
        IRQ_LOCK(MMPF_Audio_UpdatePrPtr(samples);)
        
#if (SUPPORT_MP4) || (SUPPORT_MTS)
        if(PCAM_USB_GetAudioWorkMode(MMPF_AUDIO_WORK_MODE_TS_MP4) == MMPF_AUDIO_WORK_STATUS_DONE){
            //encodeAACfile();   
            if(((gsAudioRecEvent & EVENT_DATA_ENC_AUDIO) == 0) && AAC_Audio_IsSlotFull()){
                gsAudioRecEvent |= EVENT_DATA_ENC_AUDIO;
                MMPF_OS_SetFlags(SYS_Flag_Hif, SYS_FLAG_AUDIOREC, MMPF_OS_FLAG_SET);            
            }
        }
        
        //Only TS case.
        if(PCAM_USB_GetAudioWorkMode(MMPF_AUDIO_WORK_MODE_UAC) != MMPF_AUDIO_WORK_STATUS_DONE){
            update_rd_ptr = 1;
        }

        if(update_rd_ptr==1){
            IRQ_LOCK(MMPF_Audio_UpdateRdPtr(samples);)
        }
#endif

    }
}
#endif
#endif
